﻿using System;
using System.Net;
using System.Collections;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Text;

namespace GLLog.Net
{
    /// <summary>
    /// TCP短连接服务器端
    /// </summary>
    public class TcpSvr
    {
        #region 字段
        /// <summary>
        /// 默认的服务器最大连接客户端端数据
        /// </summary>
        public string IP;

        /// <summary>
        /// 默认的服务器最大连接客户端端数据
        /// </summary>
        public int DefaultMaxClient = 512;

        /// <summary>
        /// 服务器程序使用的端口
        /// </summary>
        public ushort _port = 8419;

        /// <summary>
        /// 服务器程序允许的最大客户端连接数
        /// </summary>
        public ushort _maxClient = 512;

        /// <summary>
        /// 当前的连接的客户端数
        /// </summary>
        private int _clientCount;

        /// <summary>
        /// 服务器的运行状态
        /// </summary>
        private bool _isRun;

        /// <summary>
        /// 保存所有客户端会话的哈希表
        /// </summary>
        private Hashtable _sessionTable;

        /// <summary>
        /// 服务器使用的异步Socket类,
        /// </summary>
        private Socket _svrSock;
        #endregion

        #region 属性
        /// <summary>
        /// 当前的连接的客户端数
        /// </summary>
        public int clientCount
        {
            get
            {
                return _clientCount;
            }
        }

        /// <summary>
        /// 服务器的运行状态
        /// </summary>
        public bool isRun
        {
            get
            {
                return _isRun;
            }
        }

        /// <summary>
        /// 保存所有客户端会话的哈希表
        /// </summary>
        public Hashtable sessionTable
        {
            get
            {
                return _sessionTable;
            }
        }

        /// <summary>
        /// 服务器使用的异步Socket类,
        /// </summary>
        public Socket svrSock
        {
            get
            {
                return _svrSock;
            }
        }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ip">服务器IP地址</param>
        /// <param name="port">服务器端监听的端口号</param>
        /// <param name="maxClient">服务器能容纳客户端的最大能力</param>
        /// <param name="maxClient">服务器能容纳客户端的最大能力</param>
        public TcpSvr(string ip, ushort port, ushort maxClient, int defaultmaxclient)
        {
            IP = ip;
            DefaultMaxClient = defaultmaxclient;
            _port = port;
            _maxClient = maxClient;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public TcpSvr()
        {
            IP = Comms.Comms.GetServerIP();
        }
        #endregion

        #region 公有方法
        /// <summary>
        /// 启动服务器程序,开始监听客户端请求
        /// </summary>
        public virtual void Start()
        {
            if (_isRun)
            {
                throw (new Exception("TcpSvr已经在运行."));
            }
            _sessionTable = new Hashtable(DefaultMaxClient);
            _svrSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPEndPoint iep = new IPEndPoint(IPAddress.Parse(IP), _port);
            _svrSock.Bind(iep);
            _svrSock.Listen(DefaultMaxClient);
            _svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
            _isRun = true;
        }

        /// <summary>
        /// 停止服务器程序,所有与客户端的连接将关闭
        /// </summary>
        public virtual void Stop()
        {
            if (!_isRun)
            {
                throw (new Exception("TcpSvr已经停止"));
            }
            _isRun = false;
            if (_svrSock.Connected)
            {
                _svrSock.Shutdown(SocketShutdown.Both);
            }
            CloseAllClient();
            _svrSock.Close();
            _sessionTable = null;
        }

        /// <summary>
        /// 关闭所有的客户端会话,与所有的客户端连接会断开
        /// </summary>
        public virtual void CloseAllClient()
        {
            foreach (Session client in _sessionTable.Values)
            {
                client.Close();
            }
            _clientCount = 0;
            _sessionTable.Clear();
        }

        /// <summary>
        /// 关闭一个与客户端之间的会话
        /// </summary>
        /// <param name="closeClient">需要关闭的客户端会话对象</param>
        public virtual void CloseSession(Session closeClient)
        {
            if (closeClient != null)
            {
                _sessionTable.Remove(closeClient.ID);
                _clientCount--;
                closeClient.Close();
            }
        }
        #endregion

        #region 受保护方法
        /// <summary>
        /// 客户端连接处理
        /// </summary>
        protected virtual void AcceptConn(IAsyncResult iar)
        {
            Socket oldserver = (Socket)iar.AsyncState;
            Socket client = oldserver.EndAccept(iar);
            Session newSession = new Session(client);
            try
            {
                if (_clientCount == _maxClient)
                {
                    throw (new Exception("已到达最大连接数"));
                }
                else
                {
                    _clientCount++;
                    _sessionTable.Add(newSession.ID, newSession);
                    newSession.RecvDataBuffer = new byte[16 * 1024];
                    client.BeginReceive(newSession.RecvDataBuffer, 0, Protocol.pack_len, SocketFlags.None, new AsyncCallback(ReceiveData), newSession);
                }
            }
            catch (Exception ex)
            {
                newSession.Close();
                throw new Exception(ex.Message);
            }
            finally
            {
                _svrSock.BeginAccept(new AsyncCallback(AcceptConn), _svrSock);
            }
        }

        /// <summary>
        /// 接收处理数据包
        /// </summary>
        protected virtual void ReceiveData(IAsyncResult iar)
        {
            Session sendDataSession = (Session)iar.AsyncState;
            Socket client = sendDataSession.ClientSocket;
            IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
            Int64 ipnum = Int64.Parse(clientep.Address.ToString().Replace(".", ""));
            try
            {
                int recv = client.EndReceive(iar);
                Protocol p = new Protocol();
                p.AnalyzePack(client, sendDataSession.RecvDataBuffer);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                CloseClient(client);
            }
        }

        /// <summary>
        /// 关闭一个客户端Socket,首先需要关闭Session
        /// </summary>
        protected virtual void CloseClient(Socket client)
        {
            Session closeClient = FindSession(client);
            if (closeClient != null)
            {
                CloseSession(closeClient);
            }
            else
            {
                throw (new Exception("需要关闭的Socket对象不存在"));
            }
        }
        #endregion

        #region 私有方法
        /// <summary>
        /// 通过Socket对象查找Session对象
        /// </summary>
        private Session FindSession(Socket client)
        {
            SessionId id = new SessionId((int)client.Handle);
            return (Session)_sessionTable[id];
        }
        #endregion
    }
}
